#include <string>
#include <memory>
#include <vector>
#include <node_api.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>

#include "log/serialport_log_wrapper.h"
#include "i_serialport_client.h"
#include "x_napi_tool.h"
#include "serial_async_callback.h"
#include "serial_opt.h"
#include "serialport_types.h"
#include <iostream> 
#include "napi/native_api.h"
#include "napi/native_common.h"
#include <hilog/log.h>

int32_t SetOptions(int32_t fd, int32_t speeds, int32_t bits, int32_t events, int32_t stops)
{
	struct termios newtio, oldtio;

	if(tcgetattr(fd, &oldtio) != 0)  
	{ 
		SERIALPORT_LOGI("tcgetattr failed");
		return TCGETATTR_ERROR;
	}
	//修改输出模式，原始数据输出  
	bzero(&newtio, sizeof(newtio)); 
	newtio.c_cflag &=~(OPOST);
	//屏蔽其他标志位
	newtio.c_cflag |= (CLOCAL | CREAD );
	newtio.c_cflag &= ~CSIZE;
	newtio.c_cflag &= ~CSIZE;
	newtio.c_cflag &= ~CSIZE;
	newtio.c_cflag &= ~CSIZE;
	//设置数据位
	switch(bits)  
	{ 
		case 7:  
			newtio.c_cflag |= CS7;  
			break;  
		case 8:  
			newtio.c_cflag |= CS8;  
			break;  
		default:
			SERIALPORT_LOGI("databits set failed");
			return DATABITSET_ERROR;  
	}
	//设置校验位  
	switch(events)  
	{  
		case 0:  
		case 'N':  //无奇偶校验位  
			newtio.c_cflag &= ~PARENB;  
			newtio.c_iflag &= ~INPCK;  
			break;  
		case 1:  
		case 'O':    //设置为奇校验  
			newtio.c_cflag |= ( PARODD | PARENB );  
			newtio.c_iflag |= ( INPCK | ISTRIP );  
			break;  
		case 2:  
		case 'E':  //设置为偶校验  
			newtio.c_iflag |= ( INPCK |ISTRIP );  
			newtio.c_cflag |= PARENB;  
			newtio.c_cflag &= ~PARODD;  
			break;  
		default: 
			SERIALPORT_LOGI("events set failed");
			return EVENTSET_ERROR;  
	}
	//设置停止位  
	switch(stops)
	{
		case 1:
			newtio.c_cflag &= ~CSTOPB;
			break;
		case 2:
			newtio.c_cflag |= CSTOPB;
			break;
		default :
			SERIALPORT_LOGI("stop set failed");
			return STOPBITSET_ERROR;
	}
	//设置波特率  
	switch(speeds)  
	{  
		case 2400:  
			cfsetispeed(&newtio, B2400 );  
			cfsetospeed(&newtio, B2400 );  
			break;  
		case 4800:  
			cfsetispeed(&newtio, B4800 );  
			cfsetospeed(&newtio, B4800 );  
			break;    
		case 9600:  
			cfsetispeed(&newtio, B9600 );  
			cfsetospeed(&newtio, B9600 );  
			break;    
		case 115200:  
			cfsetispeed(&newtio, B115200 );  
			cfsetospeed(&newtio, B115200 );  
			break;  
		case 460800:  
			cfsetispeed(&newtio, B460800 );  
			cfsetospeed(&newtio, B460800 );  
			break;  
		default:
			SERIALPORT_LOGI("bandrate set failed");
			return BANDRATE_ERROR;  
	}
	//设置等待时间和最小接收字符  
	newtio.c_cc[VTIME] = 0;    
	newtio.c_cc[VMIN] = 0;     
	//VTIME=0，VMIN=0，不管能否读取到数据，read都会立即返回。  

	//输入模式  
	newtio.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);  
	//设置数据流控制  
	//newtio.c_iflag &= ~(IXON|IXOFF|IXANY); //使用软件流控制  
	//如果发生数据溢出，接收数据，但是不再读取 刷新收到的数据但是不读  
	tcflush( fd, TCIFLUSH );
	tcflush( fd, TCOFLUSH );
	//激活配置 (将修改后的termios数据设置到串口中）  
	if( tcsetattr(fd, TCSANOW, &newtio ) != 0 )  
	{  
		SERIALPORT_LOGI("tcsetattr failed");
		return TCSETATTR_ERROR;  
	} 
	return OPTION_SUCCESS;
}

int32_t OpenSerial(const char *dev)
{
	int32_t ret;
	
	ret = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
	if(ret < 0)
		SERIALPORT_LOGI("open file failed:%d\n", ret);
	return ret;
}

int32_t CloseSerial(int32_t fd)
{
	int32_t ret;
	
	ret = close(fd);
	return ret;
	
}

int32_t SendData(int32_t fd, uint8_t *data, int32_t len)
{
	int32_t ret;
	
	tcflush(fd, TCIFLUSH);
	ret = write(fd, data, len);
	return ret;
}


int32_t RecvDat(int32_t fd, uint8_t *data, int32_t len, int32_t wTimeOut)
{
	int32_t ret = -1;
	fd_set set;
	struct timeval timeout;
	int32_t iWriteSum= 0;
	int32_t iWriteOneNum = 0;
	int32_t cnt = wTimeOut;
	int32_t i = 0;
	FD_ZERO(&set);
	FD_SET(fd, &set);
	timeout.tv_sec = wTimeOut / 1000;
	timeout.tv_usec = (wTimeOut % 1000) * 1000;
	ret = select(fd + 1, &set, NULL, NULL, &timeout);
	if(ret <= 0){
		SERIALPORT_LOGI("read select failed:%d\n", ret);
		printf("read select failed:%d\n", ret);
		return ret;
	}
	while(iWriteSum < len)
	{
		iWriteOneNum = read(fd, data + iWriteSum, len - iWriteSum);
		if(iWriteOneNum < 0)
		{
			printf("read file failed:%d\n", iWriteOneNum);		
			return ret;
		}
		if(i++ >= cnt){
			printf("read file timeout:%d\n", cnt);				
			return ret;
		}
		iWriteSum += iWriteOneNum;
		usleep(1000);
	}
	return iWriteSum;
}


int main(int argc,char* argv[]) {

	int i;
	int32_t fd;
	int32_t ret;
	uint8_t temp[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
	uint8_t recvtemp[10];
	fd = OpenSerial("/dev/ttyS4");
	if(fd < 0)
	{
		printf("open uart failed:%d\n", fd);
	}
	SetOptions(fd, 9600, 8, 0, 1);
	ret = SendData(fd, temp, 8);
	if(ret < 0)
	{
		printf("SendData failed:%d\n", fd);		
	}
	sleep(3);
	ret = RecvDat(fd, recvtemp, 8, 1000);
	if(ret < 0)
	{
		printf("RecvDat failed:%d\n", fd);
	}
	printf("RecvDat length:%d\n", ret);
	for(i=0; i< ret; i++)
		printf("%02x ", recvtemp[i]);
	printf("\n");
	CloseSerial(fd);
	return 0;
}